#ifndef PSO_PARTICLE_HPP_
#   define PSO_PARTICLE_HPP_

#	include "PSOTools.hpp"
#	include "Solvers.hpp"

#	include <vector>

struct	PSOVector
{
	PSOVector(unsigned inSize)
		: veData(inSize, 0.), veFitness(99999999.)
	{}
	
	PSOVector(const std::vector<double>& inV)
		: veData(inV), veFitness(99999999.)
	{}
		
	double&	operator[](unsigned inIndex)
	{
		return (veData[inIndex]);
	}
	
	double	operator[](unsigned inIndex) const
	{
		return (veData[inIndex]);
	}
	
	std::vector<double>		veData;
	double					veFitness;
};


class PSOParticle
{
    protected:
		static 	VND*			PPVND;
	
	public:
		static 	void			Init(VRPTW&	inVRPTW);
		
		
		
		static double	getDistanceBetween(const PSOParticle& in1, const PSOParticle& in2);
    
        PSOParticle(VRPTW&	inVRPTW, unsigned inVehiclesMax)
			: 	paVRPTW(inVRPTW),
				paVehiclesMax(inVehiclesMax),
				paX(inVRPTW.size() + (inVehiclesMax << 1)),
				paXPrev(inVRPTW.size() + (inVehiclesMax << 1)),
				paPBest(inVRPTW.size() + (inVehiclesMax << 1)),
				paLBest(inVRPTW.size() + (inVehiclesMax << 1)),
				paNBest(inVRPTW.size() + (inVehiclesMax << 1)),
				paGBest(inVRPTW.size() + (inVehiclesMax << 1)),
				paVelo(inVRPTW.size() + (inVehiclesMax << 1)),
				paVehicleRef(inVehiclesMax),
				paVehicleEndDate(inVehiclesMax),
				paSol(inVRPTW)
        {
			PSOParticle::Init(inVRPTW);
			
			for (unsigned i = 0 ; i < paX.size() ; i++)
			{
				paX[i] = random_position();
				paVelo[i] = 0.;
			}
			
			paXPrev.veData = paX;
			paPBest.veData = paX;
			paLBest.veData = paX;
			paNBest.veData = paX;
			paGBest.veData = paX;
			paMatrix.clear();
			memset(&paSolEval, 0, sizeof(Sol::Eval));
		}
		
		void		reset()
		{
			for (unsigned i = 0 ; i < paX.size() ; i++)
			{
				paX[i] = random_position();
				paVelo[i] = 0.;
			}
			
			this->decode();
			
			paXPrev.veData = paX;
			paXPrev.veFitness = this->getFitness();
			paPBest.veData = paX;
			paPBest.veFitness = this->getFitness();
			paLBest.veData = paX;
			paLBest.veFitness = this->getFitness();
			paNBest.veData = paX;
			paNBest.veFitness = this->getFitness();
			paGBest.veData = paX;
			paGBest.veFitness = this->getFitness();
			
			paMatrix.clear();
			paSol.clear();
			
			
			
			memset(&paSolEval, 0, sizeof(Sol::Eval));
		}
		
		void		resetD(unsigned inNVehiclesMax)
		{
			unsigned	dim = paVRPTW.size() + (inNVehiclesMax << 1);
			
			paVehiclesMax = inNVehiclesMax;
			
			paXPrev.veData.resize(dim);
			paPBest.veData.resize(dim);
			paLBest.veData.resize(dim);
			paNBest.veData.resize(dim);
			paGBest.veData.resize(dim);
			paVehicleRef.resize(inNVehiclesMax);
			paVehicleEndDate.resize(inNVehiclesMax);
			this->reset();
		}
		
		double		getFitness() const;

		
		unsigned	getNVehicles() const
		{			
			return (paSolEval.seVehicles);
		}
        
        std::string	toString() const
        {
			char buffer[0x1000];
			std::string		str;
			
			str = "POS = {";
			for (unsigned i = 0 ; i < paX.size() ; i++)
			{
				sprintf(buffer, "%.2f", paX[i]);
				str += buffer;
				str += ";";
			}
			str += "} \n";
			
			str += "VELO = {";
			for (unsigned i = 0 ; i < paVelo.size() ; i++)
			{
				sprintf(buffer, "%.2f", paVelo[i]);
				str += buffer;
				str += ";";
			}
			str += "} \n";
			
			return str;
		}
		
		std::string	toFitnessString() const
		{
			char buffer[0x1000];
			
			sprintf(buffer, "{ X:%.2f ; P:%.2f ; L:%.2f ; N:%.2f ; G:%.2f }",
							this->getFitness(),
							paPBest.veFitness,
							paLBest.veFitness,
							paNBest.veFitness,
							paGBest.veFitness);
							
			return (buffer);
		}
		
        static unsigned        NRand;
        float		decode();
        
		VRPTW&						paVRPTW;
		unsigned					paVehiclesMax;
		
		std::vector<double>			paX;
		
		PSOVector					paXPrev;
		PSOVector					paPBest;
		PSOVector					paLBest;
		PSOVector					paNBest;
		PSOVector					paGBest;
		
		bool						paBadSolution;
		
        std::vector<double>			paVelo;
        
        std::vector< std::pair<double, double> >		paVehicleRef;
        std::vector<double>								paVehicleEndDate;
        
        Sol::Eval					paSolEval;
        Sol							paSol;
        
        std::multimap<double, unsigned>		paMatrix;
};


#endif
